package com.freewater.javabase.demo.jackson.serialization;

import com.fasterxml.jackson.annotation.JsonKey;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

@Slf4j
public class SerializationDemo {
    public static void main(String[] args) throws JsonProcessingException {
        serializationSimpleMap();
        serializationCustomKey1();
        serializationCustomKey2();
        serializationCustomKey3();
    }

    public static void serializationSimpleMap() throws JsonProcessingException {
        Map<String, String> map = Maps.newHashMap();
        map.put("key", "value");
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(map);
        log.info("{}", json);
    }

    public static void serializationCustomKey1() throws JsonProcessingException {
        Map<MyPair, String> map = Maps.newHashMap();
        map.put(new MyPair("123", "456"), "value");
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(map);
        log.info("{}", json);
    }

    public static void serializationCustomKey2() throws JsonProcessingException {
        User user = new User(ImmutableMap.of(new Date(), "value"));
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(user);
        log.info("{}", json);
    }

    public static void serializationCustomKey3() throws JsonProcessingException {
        Map<Fruit, Fruit> map = Maps.newHashMap();
        Fruit fruit = new Fruit("123", "456");
        map.put(fruit, fruit);
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(map);
        log.info("{}", json);
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    static class MyPair {
        private String first;
        private String second;

        @JsonValue
        public String myToString() {
            return first + "_and_" + second;
        }
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    static class User {

        @JsonSerialize(keyUsing = MyDateSerializer.class)
        private Map<Date, String> dayMap;
    }

    static class MyDateSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date date,
                              JsonGenerator jsonGenerator,
                              SerializerProvider serializerProvider) throws IOException {
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            jsonGenerator.writeFieldName(date == null ? "null" : formatter.format(date));
        }
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    static class Fruit {
        private String variety;

        @JsonKey
        private String name;

        @JsonValue
        public String getFullName() {
            return this.variety + "_" + this.name;
        }
    }
}
